μ λ€λ¦ νλ‘κ·Έλλ°κ³Ό νμ μμ μ΄ μ€ν¬μΈ λΆμμ μΉλͺ μ μΈ λ°μ΄ν° μ€λ₯λ₯Ό μ΄λ»κ² μ κ±°νμ¬, λ μ λ’°ν μ μκ³ νμ₯ κ°λ₯νλ©° ν΅μ°°λ ₯ μλ μ±λ₯ λͺ¨λΈμ μ΄λλμ§ νꡬν©λλ€.
μ λ€λ¦ μ€ν¬μΈ λΆμ: μ±λ₯ λΆμμ μν νμ μμ (Type-Safe) κΈ°λ° κ΅¬μΆ
μ€ν¬μΈ λ°μ΄ν°μ μ€μμ±
μλ¦¬νΈ μ€ν¬μΈ μ μΈκ³μμ λ¨ νλμ κ²°μ μ μ±νΌμΈμ νμ΄νκ³Ό μ€λ§μ€λ¬μ΄ μμ¦μ μ°¨μ΄λ₯Ό λ§λ€ μ μμ΅λλ€. μλ°±λ§ λ¬λ¬μ μ μ μ΄μ , λ§ν μ μ λ³κ²½, μμ¦ λ΄λ΄ μ§νλλ νλ ¨ κ³ν λ± λͺ¨λ κ²μ΄ μ μ λ λ°μ΄ν°μ μν΄ μ’μ°λ©λλ€. μ°λ¦¬λ μ λ‘ μλ λ°μ΄ν° μμ§ μλμ μ§μ νμ΅λλ€. GPS νΈλ컀λ λ¬λ¦° λͺ¨λ λ―Έν°λ₯Ό λͺ¨λν°λ§νκ³ , κ΄ν μμ€ν μ κ²½κΈ°μ₯ λ΄ λͺ¨λ μμ§μμ ν¬μ°©νλ©°, μ체 μΈμ μΌμλ μ€μκ° μ리 λ°μ΄ν°λ₯Ό μ€νΈλ¦¬λ°ν©λλ€. μ΄λ¬ν λ°μ΄ν°μ νμλ μλ‘μ΄ ν΅μ°°λ ₯μ μ§νμ μ½μνμ§λ§, λμμ λ§λν λμ κ³Όμ λ₯Ό μ μν©λλ€: λ°μ΄ν° νμ§κ³Ό λ¬΄κ²°μ± λ³΄μ₯μ λλ€.
λ€μ μλ리μ€λ₯Ό μμν΄ λ³΄μμμ€. μ€ν¬μΈ κ³Όννμ΄ μ μ νΌλ‘ κ΄λ¦¬λ₯Ό μν΄ GPS λ°μ΄ν°λ₯Ό λΆμν©λλ€. ν λΆμκ°κ° ν΅μ¬ μ μλ₯Ό 'λ λ μ‘΄'μΌλ‘ νμνλ λͺ¨λΈμ ꡬμΆν©λλ€. μ½μΉμ§μ λ°μ΄ν°λ₯Ό μ λ’°νμ¬ μ€μν κ²½κΈ°μ ν΄λΉ μ μλ₯Ό μ¬κ² νκ³ , νμ κ²°κ΅ ν¨λ°°ν©λλ€. κ²½κΈ° ν κ°μ¬ κ²°κ³Ό μ€λ₯μ κ·Όλ³Έ μμΈμ΄ λ°νμ‘μ΅λλ€. ν λ°μ΄ν° νμ΄νλΌμΈμ 거리λ₯Ό μΌλ λ¨μλ‘ λ³΄κ³ νκ³ , λ€λ₯Έ νμ΄νλΌμΈμ λ―Έν° λ¨μλ‘ λ³΄κ³ νλ κ²μ λλ€. λͺ¨λΈμ 무μμμ μΌλ‘ μ ν λ€λ₯Έ λ¨μμ λ°μ΄ν°λ₯Ό λνμ¬ μνν μ λλ‘ λΆμ νν ν΅μ°°λ ₯μ μμ±νμ΅λλ€. μ΄κ²μ κ°μμ λ¬Έμ κ° μλλΌ μ μΈκ³ λΆμνμκ² λ§€μΌ μ§λ©΄νλ νμ€μ λλ€.
ν΅μ¬ λ¬Έμ λ μμ λ°μ΄ν°κ° μ’ μ’ μ§μ λΆνκ³ , μΌκ΄μ±μ΄ μμΌλ©°, μ¬λ λλ μμ€ν μ€λ₯μ μ·¨μ½νλ€λ κ²μ λλ€. μΌκ΄μ±μ κ°μ νλ κ²¬κ³ ν νλ μμν¬ μμ΄λ μ°λ¦¬λ 'λ°μ΄ν° κΈ°λ°μ μΆμΈ‘' μΈκ³μμ μ΄μλ©λλ€. ν΄κ²°μ± μ λ μ κ΅ν μκ³ λ¦¬μ¦μ μλ κ²μ΄ μλλΌ, λ κ°λ ₯ν κΈ°λ°μ μμ΅λλ€. μ¬κΈ°μμ μννΈμ¨μ΄ 곡νμ μμΉ, νΉν νμ μμ (type safety)κ³Ό μ λ€λ¦ νλ‘κ·Έλλ°(generic programming)μ΄ νλ μ€ν¬μΈ λΆμκ°μκ² μμ΄μλ μ λ λκ΅¬κ° λ©λλ€.
ν΅μ¬ λ¬Έμ μ΄ν΄: νμ μ΄ μλ λ°μ΄ν°μ μνμ±
λ§μ λΆμ νκ²½, νΉν Pythonμ΄λ JavaScriptμ κ°μ΄ μ격ν κ°μ μμ΄ λμ μΌλ‘ νμ μ΄ μ§μ λλ μΈμ΄λ₯Ό μ¬μ©νλ νκ²½μμλ λ°μ΄ν°κ° μ’ μ’ μ«μ, λ¬Έμμ΄, λΆλ¦¬μΈκ³Ό κ°μ μμ κ°μ μ§ν©μΌλ‘ μ·¨κΈλμ΄ λμ λ리λ κ°μ²΄μ μ μ₯λ©λλ€. μ΄λ¬ν μ μ°μ±μ λΉ λ₯Έ νλ‘ν νμ΄νμ κ°λ ₯νμ§λ§, μμ€ν μ΄ νμ₯λ¨μ λ°λΌ μνμΌλ‘ κ°λ μ°¨κ² λ©λλ€.
νλ μ΄μ΄μ μΈμ λ°μ΄ν°λ₯Ό λνλ΄λ κ°λ¨ν μμ¬ μ½λ μμ λ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€.
μμ 1: λ¨μ νΌλ μ¬μ
ν λΆμκ°κ° μ μκ° μ»€λ²ν μ΄ κ³ κ°λ 거리λ₯Ό κ³μ°νλ €κ³ ν©λλ€. λ°μ΄ν°λ λ κ°μ λ€λ₯Έ μΆμ μμ€ν μμ λμ΅λλ€.
// Data from System A (International Standard)
let session_part_1 = {
player_id: 10,
high_speed_running: 1500 // Assumed to be in meters
};
// Data from System B (Used by a US-based league)
let session_part_2 = {
player_id: 10,
high_speed_running: 550 // Assumed to be in yards
};
// A naive function to calculate total load
function calculateTotalDistance(data1, data2) {
// The function has no way of knowing the units are different!
return data1.high_speed_running + data2.high_speed_running;
}
let total_load = calculateTotalDistance(session_part_1, session_part_2);
// Result: 2050. But what does it mean? 2050 'distance units'?
// The reality: 1500 meters + 550 yards (approx. 503 meters) = ~2003 meters.
// The calculated result is off by a significant margin.
λ¨μλ₯Ό κ°μ νλ νμ μμ€ν μ΄ μμΌλ©΄, μ΄ μ€λ₯λ μ 체 λΆμ νμ΄νλΌμΈμ ν΅ν΄ μ‘°μ©ν μ νλμ΄ λͺ¨λ νμ κ³μ° λ° μκ°νλ₯Ό μ€μΌμν΅λλ€. μ΄ λ°μ΄ν°λ₯Ό 보λ μ½μΉλ μ μκ° μΆ©λΆν μ΄μ¬ν νλ ¨νμ§ μκ±°λ, λ°λλ‘ κ³Όλ‘νκ³ μλ€κ³ μλͺ» κ²°λ‘ λ΄λ¦΄ μ μμ΅λλ€.
μμ 2: λ°μ΄ν° νμ λΆμΌμΉ
μ΄ κ²½μ°, ν λΆμκ°κ° μ ν λμ΄ λ°μ΄ν°λ₯Ό μ§κ³νκ³ μμ΅λλ€. ν μμ€ν μ λ―Έν° λ¨μμ μ«μλ‘ κΈ°λ‘νλ λ°λ©΄, λ€λ₯Έ μ€λλ μμ€ν μ μ€λͺ μ μΈ λ¬Έμμ΄λ‘ κΈ°λ‘ν©λλ€.
let jump_data_api_1 = { jump_height: 0.65 }; // meters
let jump_data_manual_entry = { jump_height: "62 cm" }; // string
function getAverageJump(jumps) {
let total = 0;
for (const jump of jumps) {
total += jump.jump_height; // This will cause an error!
}
return total / jumps.length;
}
let all_jumps = [jump_data_api_1, jump_data_manual_entry];
// Calling getAverageJump(all_jumps) would result in:
// 0.65 + "62 cm" -> "0.6562 cm"
// This is a nonsensical string concatenation, not a mathematical sum. The program might crash or produce NaN (Not a Number).
μ΄λ¬ν μ€λ₯μ κ²°κ³Όλ μ¬κ°ν©λλ€. κ²°ν¨ μλ ν΅μ°°λ ₯, μλͺ»λ μ μ νκ°, λΆμ€ν μ λ΅μ κ²°μ , κ·Έλ¦¬κ³ μ μ΄μ λ°μν΄μλ μ λ λ²κ·Έλ₯Ό μ°ΎλλΌ λ°μ΄ν° κ³Όνμλ€μ΄ λλΉνλ μλ§μ μκ°. μ΄κ²μ΄ νμ μμ νμ§ μμ μμ€ν μ΄ μΉλ₯΄λ λκ°μ λλ€.
ν΄κ²°μ± μκ°: νμ μμ (Type Safety)κ³Ό μ λ€λ¦ νλ‘κ·Έλλ°(Generic Programming)
μ λ’°ν μ μλ λΆμ κΈ°λ°μ ꡬμΆνλ €λ©΄ μ»΄ν¨ν° κ³Όνμ λ κ°μ§ κ°λ ₯ν κ°λ μ μ±νν΄μΌ ν©λλ€. μ΄λ€μ κ²¬κ³ νλ©΄μλ μ μ°ν μμ€ν μ λ§λ€κΈ° μν΄ ν¨κ» μλν©λλ€.
νμ μμ μ΄λ 무μμΈκ°?
ν΅μ¬μ μΌλ‘ νμ μμ μ νΈνλμ§ μλ λ°μ΄ν° νμ κ°μ μ°μ°μ λ°©μ§νλ μ μ½ μ‘°κ±΄μ λλ€. νλ‘κ·Έλλ° μΈμ΄λ νκ²½μ μν΄ κ°μ λλ κ·μΉμ μ§ν©μ΄λΌκ³ μκ°νμμμ€. '거리'λ‘ μ μλ λ³μμ μ€μλ‘ 'μ§λ'μ μΆκ°ν μ μλλ‘ λ³΄μ₯ν©λλ€. νλ μ΄μ΄ λ°μ΄ν° λͺ©λ‘μ κΈ°λνλ ν¨μκ° ν μ€νΈ λ¬Έμμ΄μ΄λ λ¨μΌ μ«μκ° μλ μ νν κ·Έκ²μ λ°λλ‘ λ³΄μ₯ν©λλ€.
ν¨κ³Όμ μΈ λΉμ λ μ κΈ° νλ¬κ·Έμ λλ€. μ λ½ νλ¬κ·Έ(Type F)λ λΆλ―Έ μμΌ(Type B)μ λ§μ§ μμ΅λλ€. μ΄ λ¬Όλ¦¬μ λΉνΈνμ±μ νμ μμ μ ν ννμ λλ€. κΈ°κΈ°κ° μ€κ³λμ§ μμ μ μ μμ€ν μ μ°κ²°λλ κ²μ λ°©μ§νμ¬ μ μ¬μ μΈ μμμ νΌν©λλ€. νμ μμ μμ€ν μ λ°μ΄ν°μ λν΄ λμΌν 보μ₯μ μ 곡ν©λλ€.
μ λ€λ¦ νλ‘κ·Έλλ°μ΄λ 무μμΈκ°?
νμ μμ μ΄ μ격ν¨κ³Ό μ νμ±μ μ 곡νλ λ°λ©΄, μ λ€λ¦ νλ‘κ·Έλλ°μ μ μ°μ±κ³Ό μ¬μ¬μ©μ±μ μ 곡ν©λλ€. νμ μμ μ ν¬μνμ§ μμΌλ©΄μ λ€μν νμ κ³Ό ν¨κ» μλν μ μλ μκ³ λ¦¬μ¦κ³Ό λ°μ΄ν° ꡬ쑰λ₯Ό μμ±νλ κΈ°μ μ λλ€.
리μ€νΈ λλ λ°°μ΄μ κ°λ
μ μκ°ν΄ 보μμμ€. νλͺ©μ μΆκ°νκ³ , νλͺ©μ μ κ±°νκ³ , νλͺ© μλ₯Ό μΈλ λ‘μ§μ μ«μ λͺ©λ‘μ΄λ , μ μ μ΄λ¦ λͺ©λ‘μ΄λ , νλ ¨ μΈμ
λͺ©λ‘μ΄λ λμΌν©λλ€. μ λ€λ¦ `List
μ€ν¬μΈ λΆμμμ μ΄λ `calculateAverage()`μ κ°μ μ λ€λ¦ ν¨μλ₯Ό ν λ²λ§ μμ±ν μ μμμ μλ―Έν©λλ€. κ·Έλ° λ€μ μ΄λ₯Ό μ¬μ©νμ¬ μ¬λ°μ λͺ©λ‘, μ€νλ¦°νΈ μλ λͺ©λ‘ λλ μ ν λμ΄ λͺ©λ‘μ νκ· μ κ³μ°ν μ μμΌλ©°, νμ μμ€ν μ μ΄λ€μ μ λ νΌν©νμ§ μλλ‘ λ³΄μ₯ν©λλ€.
νμ μμ μ€ν¬μΈ λΆμ νλ μμν¬ κ΅¬μΆ: μ€μ©μ μΈ μ κ·Ό λ°©μ
μ΄μ μ΄λ‘ μμ μ€μ΅μΌλ‘ λμ΄κ° λ΄ μλ€. TypeScript, Python(νμ ννΈ ν¬ν¨), Swift λλ Kotlinκ³Ό κ°μ μΈμ΄μμ 곡ν΅μ μΌλ‘ μ¬μ©λλ κ°λ μ μ¬μ©νμ¬ νμ μμ νλ μμν¬λ₯Ό μ€κ³νλ λ¨κ³λ³ κ°μ΄λμ λλ€.
1λ¨κ³: ν΅μ¬ λ°μ΄ν° νμ μ μ ννκ² μ μ
첫 λ²μ§Έμ΄μ κ°μ₯ μ€μν λ¨κ³λ λλ©μΈλ³ κ°λ μ `number`λ `string`κ³Ό κ°μ μμ νμ μ μμ‘΄νλ κ²μ μ€λ¨νλ κ²μ λλ€. λμ λ°μ΄ν°μ μλ―Έλ₯Ό ν¬μ°©νλ νλΆνκ³ μ€λͺ μ μΈ νμ μ μμ±νμμμ€.
μ λ€λ¦ `Metric` νμ
λ¨μ λ¬Έμ λ₯Ό ν΄κ²°ν΄ λ΄ μλ€. κ°κ³Ό λ¨μλ₯Ό μ°κ²°νλ μ λ€λ¦ `Metric` νμ μ μ μν μ μμ΅λλ€. μ΄λ λͺ¨νΈμ±μ λΆκ°λ₯νκ² λ§λλλ€.
// First, define the possible units as distinct types.
// This prevents typos like "meter" vs "meters".
type DistanceUnit = "meters" | "kilometers" | "yards" | "miles";
type MassUnit = "kilograms" | "pounds";
type TimeUnit = "seconds" | "minutes" | "hours";
type SpeedUnit = "m/s" | "km/h" | "mph";
type HeartRateUnit = "bpm";
// Now, create the generic Metric interface (or class).
// 'TUnit' is a placeholder for a specific unit type.
interface Metric<TUnit> {
readonly value: number;
readonly unit: TUnit;
readonly timestamp?: Date; // Optional timestamp
}
// Now we can create specific, unambiguous metric instances.
let sprintDistance: Metric<DistanceUnit> = { value: 100, unit: "meters" };
let playerWeight: Metric<MassUnit> = { value: 85, unit: "kilograms" };
let peakHeartRate: Metric<HeartRateUnit> = { value: 185, unit: "bpm" };
// The type system would now prevent the earlier error.
// let invalidSum = sprintDistance.value + playerWeight.value; // This is still possible, but...
// A properly designed system would not allow direct access to '.value' for arithmetic.
// Instead, you would use type-safe functions, as we'll see next.
2λ¨κ³: μ λ€λ¦ λ° νμ μμ λΆμ ν¨μ μμ±
κ°λ ₯ν νμ μ΄ μ μ리μ μμΌλ©΄ μ΄μ μ΄ νμ μμ μμ νκ² μλνλ ν¨μλ₯Ό μμ±ν μ μμ΅λλ€. μ΄λ¬ν ν¨μλ μ λ€λ¦μ μ¬μ©νμ¬ λ€μν μΈ‘μ νμ μ κ±Έμ³ μ¬μ¬μ©ν μ μμ΅λλ€.
μ λ€λ¦ `calculateAverage` ν¨μ
μ΄ ν¨μλ μΈ‘μ λͺ©λ‘μ νκ· μ κ³μ°νμ§λ§, λͺ¨λ μΈ‘μ κ°μ΄ μ νν λμΌν λ¨μλ₯Ό κ°μ§ λͺ©λ‘μμλ§ μλνλλ‘ μ μ½λ©λλ€.
function calculateAverage<TUnit>(metrics: Metric<TUnit>[]): Metric<TUnit> {
if (metrics.length === 0) {
throw new Error("Cannot calculate average of an empty list.");
}
const sum = metrics.reduce((acc, metric) => acc + metric.value, 0);
const averageValue = sum / metrics.length;
// The result is guaranteed to have the same unit as the inputs.
return { value: averageValue, unit: metrics[0].unit };
}
// --- VALID USAGE ---
let highIntensityRuns: Metric<"meters">[] = [
{ value: 15, unit: "meters" },
{ value: 22, unit: "meters" },
{ value: 18, unit: "meters" }
];
let averageRun = calculateAverage(highIntensityRuns);
// Works perfectly. The type of 'averageRun' is correctly inferred as Metric<"meters">.
// --- INVALID USAGE ---
let mixedData = [
sprintDistance, // This is a Metric, which includes "meters"
playerWeight // This is a Metric
];
// let invalidAverage = calculateAverage(mixedData);
// This line would produce a COMPILE-TIME ERROR.
// The type checker would complain that Metric is not assignable to Metric.
// The error is caught before the code even runs!
νμ μμ λ¨μ λ³ν
λ€μν μΈ‘μ μμ€ν μ μ²λ¦¬νκΈ° μν΄ λͺ μμ μΈ λ³ν ν¨μλ₯Ό μμ±ν©λλ€. ν¨μ μκ·Έλμ² μ체λ λ¬Έμμ΄μ μμ λ§μ΄ λ©λλ€.
const METERS_TO_YARDS_FACTOR = 1.09361;
function convertMetersToYards(metric: Metric<"meters">): Metric<"yards"> {
return {
value: metric.value * METERS_TO_YARDS_FACTOR,
unit: "yards"
};
}
// Usage:
let distanceInMeters: Metric<"meters"> = { value: 1500, unit: "meters" };
let distanceInYards = convertMetersToYards(distanceInMeters);
// Attempting to pass the wrong type will fail:
let weightInKg: Metric<"kilograms"> = { value: 80, unit: "kilograms" };
// let invalidConversion = convertMetersToYards(weightInKg); // COMPILE-TIME ERROR!
3λ¨κ³: 볡μ‘ν μ΄λ²€νΈ λ° μΈμ λͺ¨λΈλ§
μ΄μ μ΄λ¬ν μμμ νμ μ μ€ν¬μΈ νμ€μ λͺ¨λΈλ§νλ λ 볡μ‘ν κ΅¬μ‘°λ‘ νμ₯ν μ μμ΅λλ€.
// Define specific action types for a sport, e.g., football (soccer)
interface Shot {
type: "Shot";
outcome: "Goal" | "Saved" | "Miss";
bodyPart: "Left Foot" | "Right Foot" | "Head";
speed: Metric<"km/h">;
distanceFromGoal: Metric<"meters">;
}
interface Pass {
type: "Pass";
outcome: "Complete" | "Incomplete";
distance: Metric<"meters">;
receiverId: number;
}
// A union type representing any possible on-ball action
type PlayerEvent = Shot | Pass;
// A structure for a full training session
interface TrainingSession {
sessionId: string;
playerId: number;
startTime: Date;
endTime: Date;
totalDistance: Metric<"kilometers">;
averageHeartRate: Metric<"bpm">;
peakSpeed: Metric<"m/s">;
events: PlayerEvent[]; // An array of strongly-typed events
}
μ΄ κ΅¬μ‘°λ₯Ό μ¬μ©νλ©΄ `TrainingSession` κ°μ²΄κ° `bpm`μΌλ‘ μΈ‘μ λ `peakSpeed`λ₯Ό ν¬ν¨νκ±°λ `Shot` μ΄λ²€νΈμ `outcome`μ΄ λλ½λλ κ²μ΄ λΆκ°λ₯ν©λλ€. λ°μ΄ν° ꡬ쑰λ μ체 κ²μ¦ κΈ°λ₯μ κ°μΆκ³ μμ΄ λΆμμ ν¬κ² λ¨μννκ³ μ΄ λ°μ΄ν°λ₯Ό μ¬μ©νλ λͺ¨λ μ¬λμ΄ κ·Έ μ νν ννμ μλ―Έλ₯Ό μλλ‘ λ³΄μ₯ν©λλ€.
κΈλ‘λ² μ μ©: λ€μν μ€ν¬μΈ λ₯Ό μν ν΅ν© μ² ν
μ΄ μ λ€λ¦ μ κ·Ό λ°©μμ μ§μ ν νμ 보νΈμ±μ μμ΅λλ€. νΉμ νμ (`Shot`, `Pass`)μ μ€ν¬μΈ λ§λ€ λ€λ₯΄μ§λ§, `Metric`, `Event`, `Session`μ κΈ°λ³Έ νλ μμν¬λ μΌμ νκ² μ μ§λ©λλ€. μ΄λ₯Ό ν΅ν΄ μ‘°μ§μ μ΄λ€ μ€ν¬μΈ μλ μ μ©ν μ μλ λ¨μΌνκ³ κ²¬κ³ ν λΆμ νλ«νΌμ ꡬμΆν μ μμ΅λλ€.
- μΆκ΅¬: `PlayerEvent` νμ μλ `Tackle`, `Dribble`, `Cross`κ° ν¬ν¨λ μ μμ΅λλ€. λΆμμ `Shot`μΌλ‘ μ΄μ΄μ§λ μΌλ ¨μ μ΄λ²€νΈ 체μΈμ μ΄μ μ λ§μΆ μ μμ΅λλ€.
- λꡬ: μ΄λ²€νΈλ `Rebound`, `Assist`, `Block`, `Turnover`κ° λ μ μμ΅λλ€. μ μ λΆν μΈ‘μ μλ κ°μ λ° κ°μ νμκ° ν¬ν¨λ μ μμΌλ©°, μ ν λμ΄λ `Metric<"meters">` λλ `Metric<"inches">`(μμ ν λ³ν ν¨μμ ν¨κ»)λ‘ μΈ‘μ λ©λλ€.
- ν¬λ¦¬μΌ: λ³Όλ¬λ₯Ό μν `Delivery` μ΄λ²€νΈλ `speed: Metric<"km/h">`μ `type: "Bouncer" | "Yorker"`λ₯Ό κ°μ§ κ²μ λλ€. νμλ₯Ό μν `Shot` μ΄λ²€νΈλ `runsScored: number`λ₯Ό κ°μ§ κ²μ λλ€.
- μ‘μ (νΈλ & νλ): 400λ―Έν° κ²½μ£Όμ κ²½μ°, λ°μ΄ν° λͺ¨λΈμ μΌλ ¨μ `SplitTime` κ°μ²΄κ° λ κ²μ΄λ©°, κ° κ°μ²΄λ `{ distance: Metric<"meters">, time: Metric<"seconds"> }`κ° λ κ²μ λλ€.
- E-μ€ν¬μΈ : μ΄ κ°λ μ μλ²½νκ² μ μ©λ©λλ€. 리그 μ€λΈ λ μ λμ κ°μ κ²μμ κ²½μ°, μ΄λ²€νΈλ `AbilityUsed`, `MinionKill`, λλ `TowerDestroyed`κ° λ μ μμ΅λλ€. λΆλΉ νλ(APM)κ³Ό κ°μ λ©νΈλ¦μ μ리 λ°μ΄ν°μ λ§μ°¬κ°μ§λ‘ νμ μ΄ μ§μ λκ³ λΆμλ μ μμ΅λλ€.
μ΄ μ λ€λ¦ κΈ°λ°μ ν΅ν΄ νμ μ€ν¬μΈ μ ꡬμ λ°μ§ μλ μ¬μ¬μ© κ°λ₯ν κ΅¬μ± μμ(μκ°ν, λ°μ΄ν° μ²λ¦¬ λ° λͺ¨λΈλ§μ©)λ₯Ό ꡬμΆν μ μμ΅λλ€. μκ° κ²½κ³Όμ λ°λ₯Έ λͺ¨λ `Metric
νμ μμ μ κ·Ό λ°©μμ νμ μ μΈ μ΄μ
νμ μμ , μ λ€λ¦ νλ μμν¬λ₯Ό μ±ννλ©΄ λ¨μν λ²κ·Έλ₯Ό λ°©μ§νλ κ²μ ν¨μ¬ λ°μ΄λλ μμ²λ μ΄μ μ μ»μ μ μμ΅λλ€.
- νκ³ λΆλν λ°μ΄ν° λ¬΄κ²°μ± λ° μ λ’°μ±: μ΄κ²μ΄ κ°μ₯ μ€μν μ₯μ μ λλ€. λ°μ΄ν° νν λ° νμ κ³Ό κ΄λ ¨λ μ 체 ν΄λμ€μ λ°νμ μ€λ₯κ° μ κ±°λ©λλ€. κΈ°λ³Έ λ°μ΄ν°κ° μΌκ΄λκ³ μ ννλ€λ κ²μ μκΈ° λλ¬Έμ νμ μ κ°μ§κ³ κ²°μ μ λ΄λ¦΄ μ μμ΅λλ€. 'μ°λ κΈ°κ° λ€μ΄κ°λ©΄ μ°λ κΈ°κ° λμ¨λ€(Garbage In, Garbage Out)'λ λ¬Έμ λ κ·ΌμμμλΆν° ν΄κ²°λ©λλ€.
- λν ν₯μλ μμ°μ±: νλ κ°λ° νκ²½μ νμ μ 보λ₯Ό νμ©νμ¬ μ§λ₯μ μΈ μ½λ μμ±, μΈλΌμΈ μ€λ₯ κ²μ¬ λ° μλ 리ν©ν λ§μ μ 곡ν©λλ€. λΆμκ°μ κ°λ°μλ μ¬μν λ°μ΄ν° μ€λ₯λ₯Ό λλ²κΉ νλ λ° μκ°μ λ μ°κ³ ν΅μ°°λ ₯μ μμ±νλ λ° λ λ§μ μκ°μ 보λ λλ€.
- ν₯μλ ν νμ : νμ μ μ΄μμλ, κΈ°κ³κ° κ²μ¬νλ λ¬Έμμ ν ννμ λλ€. μλ‘μ΄ λΆμκ°κ° κΈλ‘λ² νμ ν©λ₯ν λ `session` κ°μ²΄μ 무μμ΄ ν¬ν¨λμ΄ μλμ§ μΆμΈ‘ν νμκ° μμ΅λλ€. κ·Έλ€μ λ¨μν `TrainingSession` νμ μ μλ₯Ό λ³Ό μ μμ΅λλ€. μ΄λ μ‘°μ§ μ 체μμ λ°μ΄ν°μ λν 곡μ λκ³ λͺ¨νΈνμ§ μμ μΈμ΄λ₯Ό λ§λλλ€.
- μ₯κΈ°μ μΈ νμ₯μ± λ° μ μ§λ³΄μμ±: μλ‘μ΄ μ€ν¬μΈ κ° μΆκ°λκ³ , μλ‘μ΄ λ©νΈλ¦μ΄ μΆμ λλ©°, μλ‘μ΄ λΆμ κΈ°μ μ΄ κ°λ°λ¨μ λ°λΌ μ격ν ꡬ쑰λ μμ€ν μ΄ νΌλμ λΉ μ§λ κ²μ λ°©μ§ν©λλ€. μλ‘μ΄ `Metric` λλ `Event`λ₯Ό μΆκ°νλ κ²μ μμΈ‘ κ°λ₯ν νλ‘μΈμ€μ΄λ©° κΈ°μ‘΄ μ½λλ₯Ό μμμΉ λͺ»ν λ°©μμΌλ‘ μμμν€μ§ μμ΅λλ€.
- κ³ κΈ λΆμμ μν κ²¬κ³ ν κΈ°λ°: λͺ¨λ μμ κ²¬κ³ ν λ¨Έμ λ¬λ λͺ¨λΈμ ꡬμΆν μλ μμ΅λλ€. κΉ¨λνκ³ μΌκ΄λλ©° μ ꡬ쑰νλ λ°μ΄ν°μ λν 보μ₯κ³Ό ν¨κ», λ°μ΄ν° κ³Όνμλ€μ λ°μ΄ν° μ 리 λμ νΉμ§ 곡ν λ° λͺ¨λΈ μν€ν μ²μ μ§μ€ν μ μμ΅λλ€.
λμ κ³Όμ λ° μ€μ©μ κ³ λ € μ¬ν
μ΄μ μ λͺ ννμ§λ§, νμ μμ μμ€ν μΌλ‘ κ°λ κΈΈμλ λμ κ³Όμ κ° μμ΅λλ€.
- μ΄κΈ° κ°λ° μ€λ²ν€λ: ν¬κ΄μ μΈ νμ μμ€ν μ μ μνλ κ²μ νμ μλ λμ λλ¦¬λ‘ μμ νλ κ²λ³΄λ€ λ λ§μ μ¬μ μκ°κ³Ό κ³νμ΄ νμν©λλ€. μ΄ μ΄κΈ° ν¬μλ λ λλ¦¬κ² λκ»΄μ§ μ μμ§λ§, νλ‘μ νΈ μλͺ λμ μμ²λ μ΄λμ κ°μ Έλ€μ€λλ€.
- νμ΅ κ³‘μ : λμ μΌλ‘ νμ μ΄ μ§μ λλ μΈμ΄μ μ΅μν νμ κ²½μ°, μ λ€λ¦, μΈν°νμ΄μ€ λ° νμ λ 벨 νλ‘κ·Έλλ°κ³Ό κ΄λ ¨λ νμ΅ κ³‘μ μ΄ μμ μ μμ΅λλ€. μ΄λ κ΅μ‘μ λν νμ κ³Ό μ¬κ³ λ°©μμ μ νμ μꡬν©λλ€.
- νμ μ΄ μλ μΈκ³μμ μνΈ μ΄μ©μ±: λΆμ μμ€ν μ μ§κ³΅ μνμ μ‘΄μ¬νμ§ μμ΅λλ€. μΈλΆ API, CSV νμΌ λ° μ’ μ’ νμ μ΄ μλ λ κ±°μ λ°μ΄ν°λ² μ΄μ€λ‘λΆν° λ°μ΄ν°λ₯Ό μμ§ν΄μΌ ν©λλ€. ν΅μ¬μ κ°λ ₯ν "νμ κ²½κ³"λ₯Ό λ§λλ κ²μ λλ€. μμ§ μμ μ λͺ¨λ μΈλΆ λ°μ΄ν°λ λ΄λΆ νμ μ λν΄ κ΅¬λ¬Έ λΆμλκ³ μ ν¨μ± κ²μ¬λ₯Ό λ°μμΌ ν©λλ€. μ ν¨μ± κ²μ¬μ μ€ν¨νλ©΄ λ°μ΄ν°λ κ±°λΆλ©λλ€. μ΄λ 'λλ¬μ΄' λ°μ΄ν°κ° ν΅μ¬ μμ€ν μ μ€μΌμν€λ κ²μ λ°©μ§ν©λλ€. Pydantic(Pythonμ©) λλ Zod(TypeScriptμ©)μ κ°μ λꡬλ μ΄λ¬ν μ ν¨μ± κ²μ¬ κ³μΈ΅μ ꡬμΆνλ λ° νμν©λλ€.
- μ¬λ°λ₯Έ λꡬ μ ν: ꡬνμ κΈ°μ μ€νμ λ°λΌ λ€λ¦ λλ€. TypeScriptλ μΉ κΈ°λ° νλ«νΌμ νμν μ νμ λλ€. λ°μ΄ν° κ³Όν νμ΄νλΌμΈμ κ²½μ°, μ±μν `typing` λͺ¨λκ³Ό Pydanticκ³Ό κ°μ λΌμ΄λΈλ¬λ¦¬λ₯Ό κ°μΆ Pythonμ κ°λ ₯ν μ‘°ν©μ λλ€. κ³ μ±λ₯ λ°μ΄ν° μ²λ¦¬μ κ²½μ°, Go, Rust λλ Scalaμ κ°μ μ μ νμ μΈμ΄λ μ΅λμ μμ κ³Ό μλλ₯Ό μ 곡ν©λλ€.
μ€ν κ°λ₯ν ν΅μ°°λ ₯: μμνλ λ°©λ²
λΆμ νμ΄νλΌμΈμ νμ νλ κ²μ λ¨κ±°λ¦¬ κ²½μ£Όκ° μλλΌ μ¬μ μ λλ€. λ€μμ μμνκΈ° μν λͺ κ°μ§ μ€μ©μ μΈ λ¨κ³μ λλ€.
- μκ² μμνκ³ κ°μΉλ₯Ό μ μ¦: μ 체 νλ«νΌμ ν λ²μ 리ν©ν λ§νλ €κ³ μλνμ§ λ§μμμ€. λ¨μΌνκ³ μ μ μλ νλ‘μ νΈ(μ: νΉμ λ©νΈλ¦μ μν μ λμ보λ λλ ν κ°μ§ μ νμ μ΄λ²€νΈ λΆμ)λ₯Ό μ ννμμμ€. νμκ² μ΄μ μ 보μ¬μ£ΌκΈ° μν΄ νμ μμ μ κ·Ό λ°©μμ μ¬μ©νμ¬ μ²μλΆν° ꡬμΆνμμμ€.
- ν΅μ¬ λλ©μΈ λͺ¨λΈ μ μ: μ΄ν΄ κ΄κ³μ(λΆμκ°, μ½μΉ, κ°λ°μ)λ₯Ό λͺ¨μ μ£Όμ μ€ν¬μΈ μ ν΅μ¬ μν°ν°λ₯Ό 곡λμΌλ‘ μ μνμμμ€. `Player`, `Session`, `Event`λ 무μμ ꡬμ±ν©λκΉ? κ°μ₯ μ€μν `Metrics`μ κ·Έ λ¨μλ 무μμ λκΉ? μ΄λ¬ν μ μλ₯Ό 곡μ νμ λΌμ΄λΈλ¬λ¦¬μ μ½λννμμμ€.
- μ격ν νμ κ²½κ³ μ€μ : κ²¬κ³ ν λ°μ΄ν° μμ§ κ³μΈ΅μ ꡬννμμμ€. λͺ¨λ λ°μ΄ν° μμ€μ λν΄ λ€μ΄μ€λ λ°μ΄ν°λ₯Ό μ ν¨μ± κ²μ¬νκ³ λ΄λΆμ κ°λ ₯ν νμ λͺ¨λΈλ‘ λ³ννλ νμλ₯Ό μμ±νμμμ€. 무μλΉνμμμ€. λ°μ΄ν°κ° κ·μ μ μ€μνμ§ μμΌλ©΄ νλκ·Έκ° μ§μ λκ³ κ±°λΆλμ΄μΌ νλ©°, μ§ννλλ‘ νμ©ν΄μλ μ λ©λλ€.
- νλ λꡬ νμ©: μ½λ νΈμ§κΈ°μ CI(μ§μμ μΈ ν΅ν©) νμ΄νλΌμΈμ ꡬμ±νμ¬ νμ κ²μ¬κΈ°λ₯Ό μλμΌλ‘ μ€ννλλ‘ νμμμ€. νμ κ²μ¬ ν΅κ³Όλ₯Ό λͺ¨λ μ½λ λ³κ²½μ λν νμ λ¨κ³λ‘ λ§λμμμ€. μ΄λ κ°μ λ₯Ό μλννκ³ μμ μ μν¬νλ‘μ°μ κΈ°λ³Έ λΆλΆμΌλ‘ λ§λλλ€.
- νμ§ λ¬Έν μ‘°μ±: μ΄κ²μ κΈ°μ μ μΈ λ³νλ§νΌμ΄λ λ¬Ένμ μΈ λ³νμ λλ€. νμ μμ μ 'μ΄μ 'μ λν΄ μ 체 νμ κ΅μ‘νμμμ€. μ΄κ²μ΄ κ΄λ£μ£Όμλ₯Ό μΆκ°νλ κ²μ΄ μλλΌ λ λΉ λ₯΄κ³ μ λ’°ν μ μλ ν΅μ°°λ ₯μ κ°λ₯νκ² νλ μ λ¬Έ λ±κΈ λꡬλ₯Ό ꡬμΆνλ κ²μμ κ°μ‘°νμμμ€.
κ²°λ‘ : νμ μ κ°μ§κ³ λ°μ΄ν°μμ μμ¬ κ²°μ μΌλ‘
μ€ν¬μΈ λΆμ λΆμΌλ λ¨μν μ€νλ λμνΈμ μλ λ°μ΄ν° μ λ ₯ μλλ₯Ό ν¨μ¬ λμ΄μ°μ΅λλ€. μ΄μ μ¬μ© κ°λ₯ν λ°μ΄ν°μ 볡μ‘μ±κ³Ό μμ μ¬λ¬΄ λͺ¨λΈλ§ λλ κΈ°μ μννΈμ¨μ΄ κ°λ°μμ λ³Ό μ μλ κ²κ³Ό λμΌν μμ€μ μ격ν¨κ³Ό μ λ¬Έμ±μ μꡬν©λλ€. λ°μ΄ν° 무결μ±μ λ€λ£° λ ν¬λ§μ μ λ΅μ΄ μλλλ€.
νμ μμ λ° μ λ€λ¦ νλ‘κ·Έλλ°μ μμΉμ μμ©ν¨μΌλ‘μ¨ μ°λ¦¬λ μλ‘μ΄ μΈλμ λΆμ νλ«νΌμ ꡬμΆν μ μμ΅λλ€. μ΄λ¬ν νλ«νΌμ λ μ ννκ³ μ λ’°ν μ μμ λΏλ§ μλλΌ λ νμ₯ κ°λ₯νκ³ μ μ§λ³΄μ κ°λ₯νλ©° νμ μ μ λλ€. μ΄λ μ λ’°μ κΈ°λ°μ μ 곡νμ¬ μ½μΉλ κ΄λ¦¬μκ° λ°μ΄ν° ν¬μΈνΈλ₯Ό κΈ°λ°μΌλ‘ μ€λν κ²°μ μ λ΄λ¦΄ λ μ΅λνμ νμ μ κ°μ§κ³ κ·Έλ κ² ν μ μλλ‘ λ³΄μ₯ν©λλ€. κ²½μμ΄ μΉμ΄ν μ€ν¬μΈ μΈκ³μμ κ·Έ νμ μ κΆκ·Ήμ μΈ μ°μμ λλ€.